package com.sdust.position.service.impl;

import com.sdust.feign.clients.UserFeignClient;
import com.sdust.model.position.entity.Position;
import com.sdust.model.position.vos.PositionVo;
import com.sdust.model.user.entity.User;
import com.sdust.position.service.PositionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.geo.GeoJsonPoint;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

@Service
public class PositionServiceImpl implements PositionService {

    @Autowired
    private MongoTemplate mongoTemplate;

    @Autowired
    private UserFeignClient userFeignClient;

    /**
     * 保存位置信息
     * @param position
     */
    @Override
    public void savePosition(Position position) {
        // 构造查询条件
        Query query = Query.query(Criteria.where("userId").is(position.getUserId()));

        // 设置 GeoJsonPoint
        position.setLocation(new GeoJsonPoint(
                position.getLongitude(),
                position.getLatitude()
        ));

        // 构建更新字段
        Update update = new Update()
                .set("latitude", position.getLatitude())
                .set("longitude", position.getLongitude())
                .set("altitude", position.getAltitude())
                .set("speed", position.getSpeed())
                .set("accuracy", position.getAccuracy())
                .set("timestamp", position.getTimestamp())
                .set("location", position.getLocation());

        // 执行 upsert 操作（不依赖 Position.class）
        mongoTemplate.upsert(query, update, "positions");
    }



    /**
     * 获取附近的用户
     * @param latitude
     * @param longitude
     * @param range
     * @return
     */
    @Override
    public List<PositionVo> getNearbyUsers(double latitude, double longitude, int range) {
        // 1. 构造中心点
        GeoJsonPoint center = new GeoJsonPoint(longitude, latitude);

        // 2. 使用标准查询（非NearQuery）
        Query query = Query.query(
                Criteria.where("location")
                        .nearSphere(center)
                        .maxDistance(range / 6378137.0) // 地球赤道半径6378137米
        ).addCriteria(Criteria.where("userId").ne("1"));

        // 3. 执行普通查询
        List<Position> positions = mongoTemplate.find(query, Position.class, "positions");

        // 4. 手动计算距离（因未使用geoNear）
        return positions.stream()
                .map(position -> {
                    double distance = calculateDistance(
                            latitude, longitude,
                            position.getLocation().getY(),
                            position.getLocation().getX()
                    );

                    User user = userFeignClient.getUserById(Integer.valueOf(position.getUserId()));


                    return PositionVo.builder()
                            .id(position.getId())
                            .userId(position.getUserId())
                            .userName(user != null ? user.getUserName() : null)
                            .avatarUrl(user != null ? user.getAvatarUrl() : null)
                            .latitude(position.getLocation().getY())
                            .longitude(position.getLocation().getX())
                            .distance(distance)
                            .build();
                })
                .collect(Collectors.toList());
    }

    /**
     * 使用 Haversine 公式计算两点之间的直线距离（单位：米）
     */
    private double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
        final int R = 6371; // 地球半径（千米）

        double latDistance = Math.toRadians(lat2 - lat1);
        double lonDistance = Math.toRadians(lon2 - lon1);

        double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
                + Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
                * Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);

        double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));

        return R * c * 1000; // 返回单位为米
    }

}
